/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package bolao.ui.beans;


import bolao.service.CRUDService;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author 002824992500
 */
public abstract class BaseCRUDJSFBean extends BaseJSFBean {
    private static final String OBJ_SELECIONADO = "objSelecionado";
    
    @EJB
    private CRUDService crudService;
    private String paginaListagem;
    private String paginaForm;
    private boolean facesRedirect = true;
    private static final Logger log = LoggerFactory.getLogger(BaseCRUDJSFBean.class);

    public boolean isFacesRedirect() {
        return facesRedirect;
    }

    public void setFacesRedirect(boolean facesRedirect) {
        this.facesRedirect = facesRedirect;
    }


    protected CRUDService getCrudService() {
        return crudService;
    }

    public String getPaginaForm() {
        return paginaForm + (isFacesRedirect() ? "?faces-redirect=true" : "");
    }    

    public void setPaginaForm(String paginaForm) {
        this.paginaForm = paginaForm;
    }

    public String atualizar() {
        renovarTabela();
        return null;
    }

    public String getPaginaListagem() {
        return paginaListagem + (isFacesRedirect() ? "?faces-redirect=true" : "");
    }

    public void setPaginaListagem(String paginaListagem) {
        this.paginaListagem = paginaListagem + ".xhtml";
    }

    private Class crudClass;

    protected Class getCrudClass() {
        return crudClass;
    }

    protected void setCrudClass(Class crudClass) {
        this.crudClass = crudClass;
    }

    public String criarObj() {
        try {
            setObjSelecionado(crudClass.newInstance());
            return getPaginaForm();
        } catch (Exception ex) {
            throw new RuntimeException("Não foi possível criar o objeto. " + ex.getMessage(), ex);
        }

    }

    public <T> T getObjSelecionado() {
        // Verifica se algum objeto foi guardado anteriormente para edição
        T obj = (T)getSessionVal(OBJ_SELECIONADO);
        if (obj == null || !obj.getClass().equals(this.crudClass)) {
            try {
                // Nenhum objeto foi guardado no escopo de Flash anteriormente,
                // então a página está sendo acessada para criação de um novo
                // objeto. Procede com a criação de um novo objeto.
                obj = (T) this.crudClass.newInstance();
                // Salva o objeto no escopo de Sessão para acessos posteriores
                salvaNoEscopoDeSessao(obj);
            } catch (Exception ex) {
                String err = "Erro ao criar o objeto: " + ex.getMessage();
                error(err);
                throw new RuntimeException(err, ex);
            }
        } 
        return obj;
    }

    public void setObjSelecionado(Object obj) {        
        salvaNoEscopoDeSessao(obj);
    }

    /**
     * Salva o objeto passado como argumento no escopo de Session, para que ele
     * possa estar acessível na próxima view/página.
     * @param objSelecionado objeto a ser guardado no escopo de Session
     */
    private void salvaNoEscopoDeSessao(Object objSelecionado) {
        setSessionVal(OBJ_SELECIONADO, objSelecionado);
    }

    public String salva() {
        try {
            // Salva o objeto e o guarda no escopo de Flash para posteriores
            // acessos.
            salvaNoEscopoDeSessao(salvaObjeto(getObjSelecionado()));

            // Renova a listagem de objetos para que seja exibido o novo objeto
            renovarTabela();
            keepMessages();
            info("Registro salvo com sucesso.");

            // Retorna para a página de listagem
            return this.getPaginaListagem();
        } catch (Exception e) {
            error("Erro ao tentar salvar: " + e.getMessage());
            return null;
        }
    }

    protected Object salvaObjeto(Object o) {
        return crudService.save(o);
    }
    
    public BaseCRUDJSFBean() {
    }

    @PostConstruct
    protected void setup() {};
    
    public String editarObj(Object obj) {
        try {            
            //crudService.verificaSeFoiExcluidoPorOutraSessao(this.getObjSelecionado());
            crudService.verificaSeFoiExcluidoPorOutraSessao(obj);

            setObjSelecionado(obj);

            // Redireciona para a página do formulário
            return this.getPaginaForm();
        } catch (Exception e) {
            error("Erro ao tentar editar: " + e.getMessage());
            // Em caso de erro, permanece na mesma página
            return null;
        }
    }

    public String deletarObj(Object obj) {
        try {            
            crudService.delete(obj);            
            renovarTabela();            
            info("Registro excluído com sucesso.");
        } catch (Exception e) {
            error("Erro ao tentar excluir: " + e.getMessage());
            log.error("Erro ao tentar excluir: " + e.getMessage(), e);
        }
        // Permanece na mesma página
        return null;
    }

    /**
     * Método utilizado para atualizar a listagem de objetos a serem listados
     * na tela. Deve ser chamado após a inicialização e depois da exclusão de
     * um objeto, para que a listagem possa ser atualizada com os objetos
     * restantes.
     */
    protected void renovarTabela() {};
}
